//
// Created by denglibin on 19-10-18.
//

/**
 *在编程的时候，很多时候会用到定时器，定时检测某个状态是否发生变化并进行处理。这时候，就会用到setitimer函数了。
1. 要使用setitimer函数，要包含头文件：#include <sys/time.h>
2. 该函数的原型是：int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value)
其中which参数表示类型，可选的值有：
    ITIMER_REAL：以系统真实的时间来计算，它送出SIGALRM信号。
    ITIMER_VIRTUAL：以该进程在用户态下花费的时间来计算，它送出SIGVTALRM信号。
    ITIMER_PROF：以该进程在用户态下和内核态下所费的时间来计算，它送出SIGPROF信号。
    紧接着的new_value和old_value均为itimerval结构体
    struct itimerval {
        struct timeval it_interval;  next value
        struct timeval it_value;    current value
    };

    struct timeval {
            time_t      tv_sec;         seconds
            suseconds_t tv_usec;         microseconds
    };
     itimeval又是由两个timeval结构体组成，timeval包含tv_sec和tv_usec两部分，其中tv_se为秒，tv_usec为微秒(即1/1000000秒)

 new_value参数用来对计时器进行设置，it_interval为计时间隔，it_value为延时时长
     settimer工作机制是，先对it_value倒计时，当it_value为零时触发信号，然后重置为it_interval，继续对it_value倒计时，一直这样循环下去。
    基于此机制，setitimer既可以用来延时执行，也可定时执行。
    假如it_value为0是不会触发信号的，所以要能触发信号，it_value得大于0；
     如果it_interval为零，只会延时，不会定时（也就是说只会触发一次信号)。

old_value参数，通常用不上，设置为NULL，它是用来存储上一次setitimer调用时设置的new_value值

 */

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>

void signalHandler(int signo){
    switch (signo){
        case SIGALRM:
            printf("Caught the SIGALRM signal!\n");
            break;
    }
}

static void test_setitimer(){
    signal(SIGALRM, signalHandler);
    struct itimerval new_value, old_value;
    //setitimer方法调用成功后，延时1毫秒便触发一次SIGALRM信号，以后每隔200毫秒触发一次SIGALRM信号
    new_value.it_value.tv_sec = 0; // 秒值
    new_value.it_value.tv_usec = 1000; //微妙值
    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_usec = 200 * 1000;
    setitimer(ITIMER_REAL, &new_value, &old_value);
    while (1);
}

//用setitimer实现一个alarm函数
static unsigned int my_alarm(int sec){
    struct itimerval new_value, old_value;

    new_value.it_value.tv_sec = sec; // 秒值
    new_value.it_value.tv_usec = 0; //微妙值
    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &new_value, &old_value);
    return old_value.it_value.tv_sec;
}
static void test_my_alarm(){
    signal(SIGALRM, signalHandler);
    my_alarm(2);
    while(1);
}
static int main_(){
    //test_setitimer();
    test_my_alarm();

    return 0;
}

